﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace CodeEditor
{
    
    public partial class MethodListForm : DigitalRune.Windows.Docking.DockableForm
    {
        //Eventhandler
        public delegate void EditorWindowEventHandler(Object sender, EditorWindowEventArgs e);
        //Event wird beim Hinzufügen einer Methode ausgelöst
        public event EditorWindowEventHandler EditorWindowAdded;
        public event EventHandler EditorWindowTextChanged;
        //speichert Knoten <=> EditorTabs
        private Hashtable nodesToEditorWindow = new Hashtable();

        //Zum Auslesen der Knoten und Methodeninhalte...vor allem für das Speichern,
        //das im Editor - Fenster ausgeführt wird.

        public bool IsSaved { get; set; }
        public int UserLevel { get; set; }
        /// <summary>
        /// Hashtabel mit Node - Editor - Verknüpfungen
        /// </summary>
        public Hashtable NodesAndEditorWindows
        {
            get
            {
                return nodesToEditorWindow;
            }
        }

        public MethodListForm()
        {
            InitializeComponent();
        }


        /// <summary>
        /// Wird ausgelöst, wenn eine Methode hinzugefügt wird
        /// </summary>
        /// <param name="sender">Toolstripbutton</param>
        /// <param name="e">Event Arguments</param>
        private void toolStripButtonAddMethod_Click(object sender, EventArgs e)
        {
            try
            {
                AddMethod("Method" + treeViewMethods.Nodes[0].Nodes.Count.ToString(), String.Empty);
            }
            catch (Exception ex)
            {
                new ExceptionMessageBox(ex);
            }
        }

        public void InvokeKeyPressButtonAddMethod()
        {
            toolStripButtonAddMethod_Click(this, new EventArgs());
        }

        /// <summary>
        /// Wird ausgelöst, wenn eine Node ausgewählt wurde
        /// </summary>
        /// <param name="sender">treeViewMethods</param>
        /// <param name="e">Tree View Event Arguments</param>
        private void treeViewMethods_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (nodesToEditorWindow[e.Node] != null)
            {
                //Ausgewählte Methode nur anzeigen, wenn != null
                (nodesToEditorWindow[e.Node] as MethodWindow).Show(); 
            }
            
        }

        /// <summary>
        /// Wird ausgelöst, nachdem ein Nodetext geändert wurde
        /// </summary>
        /// <param name="sender">treeViewMethods</param>
        /// <param name="e">Node Label Edit Event Arguments</param>
        private void treeViewMethods_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            MethodWindow eWindow = nodesToEditorWindow[e.Node] as MethodWindow;
            if (eWindow != null && e.Label != null)
            {
                eWindow.TabText = e.Label;
                eWindow.Settings.MethodName = eWindow.TabText;
                eWindow.Settings.NotifyPropertyChanged("MethodName");
            }
        }

        /// <summary>
        /// Wird ausgelöst, wenn auf Umbenennen geklickt wird...Kontextmenu von jeder Node
        /// </summary>
        /// <param name="sender">Button</param>
        /// <param name="e">Event Arguments</param>
        private void umbenennenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            treeViewMethods.SelectedNode.BeginEdit();
        }

        /// <summary>
        /// Wird ausgelöst, wenn mit einer Maustaste auf eine Node geklickt wird
        /// </summary>
        /// <param name="sender">treeViewMethods</param>
        /// <param name="e">Tree Node Mouse Click Event Arguments</param>
        private void treeViewMethods_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            treeViewMethods.SelectedNode = e.Node; //wichtig, damit Node auch bei Rechtsklick ausgewählt wird
        }

        /// <summary>
        /// Wird ausgelöst, bevor eine Node umbenannt wird
        /// </summary>
        /// <param name="sender">treeViewMethods</param>
        /// <param name="e">Node Label Edit Event Argumenst</param>
        private void treeViewMethods_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            //Rootnode darf nicht umbenannt werden! Sofort Abfangen und abbrechen
            if (e.Node == treeViewMethods.Nodes[0]) 
            {
                e.CancelEdit = true;
            }
        }

        /// <summary>
        /// Wird ausgelöst, wenn jemand eine Node löschen möchte
        /// </summary>
        /// <param name="sender">Button</param>
        /// <param name="e">Event Arguments</param>
        private void toolStripButtonDeleteMethod_Click(object sender, EventArgs e)
        {
            DeleteMethod(treeViewMethods.SelectedNode);
        }


        /// <summary>
        /// Wird ausgelöst, wenn jemand eine Node löschen möchte
        /// </summary>
        /// <param name="sender">Button</param>
        /// <param name="e">Event Arguments</param>
        private void löschenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Zum Löschen über das Kontextmenu wird das Click - Event des bereits
            //vorhandenen Delete - Buttons verwendet, um redundenten Code zu vermeiden
            toolStripButtonDeleteMethod_Click(sender, e);
        }



        /// <summary>
        /// Alle Methoden löschen
        /// </summary>
        public void ClearAllMethods()
        {
            foreach (TreeNode nodeToDelete in treeViewMethods.Nodes[0].Nodes)
            {
                (nodesToEditorWindow[nodeToDelete] as MethodWindow).HideOnClose = false;
                (nodesToEditorWindow[nodeToDelete] as MethodWindow).Close();
                (nodesToEditorWindow[nodeToDelete] as MethodWindow).EditorBox.TextChanged -= new EventHandler(EditorWindow_TextChanged);
                nodesToEditorWindow.Remove(nodeToDelete);
            }

            
            //Wichtig!!! Node darf nicht innerhalb der foreach - Schleife gelöscht werden,
            //da interner Schleifenzähler sonst falsch zählt!!!!!
            //Daher NICHT für jede Node die DeleteMethod aufrufen, der redundante Code ist hier gewollt!!
            
            treeViewMethods.Nodes[0].Nodes.Clear();
        }


        /// <summary>
        /// eine Methode löschen
        /// </summary>
        /// <param name="nodeToDelete">zu löschende Methode</param>
        private void DeleteMethod(TreeNode nodeToDelete)
        {
            if (nodeToDelete != null)
            {
                //Main - Methode darf nicht gelöscht werden...überprüfen:
                if (nodeToDelete != treeViewMethods.Nodes[0])
                {
                    //sicherstellen, dass Form wirklich geschlossen werden kann
                    (nodesToEditorWindow[nodeToDelete] as MethodWindow).HideOnClose = false;
                    (nodesToEditorWindow[nodeToDelete] as MethodWindow).Close();
                    (nodesToEditorWindow[nodeToDelete] as MethodWindow).EditorBox.TextChanged -= new EventHandler(EditorWindow_TextChanged);
                    nodesToEditorWindow.Remove(nodeToDelete);
                    nodeToDelete.Remove();
                }
                else
                {
                    //die Main - Methode soll doch nicht gelöscht werden :)
                    MessageBox.Show(Properties.Resources.CantDeleteMainMethodText);
                }
            }
        }



        /// <summary>
        /// methode hinzufügen
        /// </summary>
        /// <param name="methodName">Method Name</param>
        /// <param name="Content">Method Content</param>
        public void AddMethod(String methodName, String Content)
        {
            TreeNode newNode = new TreeNode((methodName == String.Empty ? "Method" + treeViewMethods.Nodes[0].Nodes.Count.ToString(): methodName), 1, 1);
            newNode.ContextMenuStrip = contextMenuStripNode;
            //Neue Node wird an Rootnode(Nodes[0]) gehängt
            treeViewMethods.Nodes[0].Nodes.Add(newNode);
            //alle Nodes ausklappen
            treeViewMethods.ExpandAll();

            MethodWindow myNewEditorWindow = new MethodWindow(false, UserLevel == 1);
            myNewEditorWindow.EditorBox.TextChanged += new EventHandler(EditorWindow_TextChanged);
            //Fenster von neuen Methoden können - im Gegensatz zur Mainmethode - geschlossen werden
            myNewEditorWindow.CloseButton = true;
            myNewEditorWindow.TabText = newNode.Text;
            myNewEditorWindow.Settings.MethodName = newNode.Text;
            //Code für neue Methode
            myNewEditorWindow.EditorText = Content;

            EditorWindowEventArgs evtArgs = new EditorWindowEventArgs(myNewEditorWindow);
            //Event feuern. Wichtig, damit neue DockableForm im Dockpanel registriert werden kann
            EditorWindowAdded(this, evtArgs);
            nodesToEditorWindow.Add(newNode, myNewEditorWindow);
        }

        public void AddMethod(String methodName, String Content, String returnType, List<MethodWindow.MethodSettings.Parameter> paramList)
        {
            TreeNode newNode = new TreeNode((methodName == String.Empty ? "Method" + treeViewMethods.Nodes[0].Nodes.Count.ToString() : methodName), 1, 1);
            newNode.ContextMenuStrip = contextMenuStripNode;
            //Neue Node wird an Rootnode(Nodes[0]) gehängt
            treeViewMethods.Nodes[0].Nodes.Add(newNode);
            //alle Nodes ausklappen
            treeViewMethods.ExpandAll();

            MethodWindow myNewEditorWindow = new MethodWindow(false, UserLevel == 1);
            myNewEditorWindow.EditorBox.TextChanged += new EventHandler(EditorWindow_TextChanged);
            //Fenster von neuen Methoden können - im Gegensatz zur Mainmethode - geschlossen werden
            myNewEditorWindow.CloseButton = true;
            myNewEditorWindow.TabText = newNode.Text;
            myNewEditorWindow.Settings.MethodName = newNode.Text;
            //Code für neue Methode
            myNewEditorWindow.EditorText = Content;
            myNewEditorWindow.Settings.ReturnType = returnType;
            myNewEditorWindow.Settings.Parameters = paramList;
            myNewEditorWindow.Settings.MethodName = methodName;
            EditorWindowEventArgs evtArgs = new EditorWindowEventArgs(myNewEditorWindow);
            //Event feuern. Wichtig, damit neue DockableForm im Dockpanel registriert werden kann
            EditorWindowAdded(this, evtArgs);
            nodesToEditorWindow.Add(newNode, myNewEditorWindow);
        }

        /// <summary>
        /// Wird ausgelöst, wenn der Text in einem EditorWindow geändert wird...gilt nicht für die Main - Methode
        /// Main - Methode: s. Editor.cs
        /// </summary>
        /// <param name="sender">EditorWindow</param>
        /// <param name="e">Event Arguments</param>
        void EditorWindow_TextChanged(object sender, EventArgs e)
        {
            //wird ausgelöst, wenn in irgendeiner Methode der Content geändert wird
            EditorWindowTextChanged(this, e);
        }

        
    }


    /// <summary>
    /// EventArg, das zusätzlich das EditorWindow der Methode enthält
    /// </summary>
    public class EditorWindowEventArgs : EventArgs
    {
        public MethodWindow CurrentEditorWindow { get; private set; }
        public EditorWindowEventArgs(MethodWindow eWindow)
        {
            CurrentEditorWindow = eWindow;
        }
        
    }
}
